########################################################
# Part of MILIM NIRDAFOT project.
# Written by H. Magal, 2014
# See details on the project at the site:
#   https://sites.google.com/site/nirdafotdownloads/home
########################################################

# standard library modules
import wx
import sys
import random
import platform
import webbrowser

# user modules
import hebrew_fixed_texts
import synonymDB
import constants
import full_list_frame
import setup
import tech_support
import GPLv3_license_acceptance

# Declare GUI Constants
MENU_FILE_EXIT          = wx.NewId()
MENU_CHECK_UPDATES      = wx.NewId()
MENU_SHOW_VERSION       = wx.NewId()
MENU_SOLVE_CURRENT_LIST = wx.NewId()
MENU_HELP_HTML          = wx.NewId()
BUTN_NEW_LIST           = wx.NewId()
MENU_WRITE_VERSION      = wx.NewId()
MENU_SHOW_FULL_LIST     = wx.NewId()
MENU_ABOUT_DLG          = wx.NewId()

class MyCustomDialog (wx.Dialog):
    #########################################
    # positional args are:
    #   1. size (as tuple (width, height))
    #   2. Dialog message (as string)
    #   3.& 4. left button and right button texts (as strings)
    #   5.& 6. left button and right button return values. (as int's)
    #########################################
    # call this Dialog Box as follows:
    #   dlg = MyCustomDialog ((width,height), 'Box main message', 'Left Button Text', 'Right Button text',
    #                         LeftButtonVal, RightButtonVal, parent=None, title='Box Title')
    #   dlg.ShowModal()
    #   rc = dlg.GetReturnCode ()
    #########################################
    def __init__ (self, size, message, lbutText, rbutText, lbutVal, rbutVal, **kw):
        super (MyCustomDialog, self).__init__ (**kw)
        self.SetSize (size)
        vbox = wx.BoxSizer (wx.VERTICAL)
        st = wx.StaticText (self, label=message)

        hbox = wx.BoxSizer (wx.HORIZONTAL)
        lButton = wx.Button (self, label=lbutText)
        rButton = wx.Button (self, label=rbutText)
        hbox.Add (lButton, flag=wx.ALL, border=5)
        hbox.Add (rButton, flag=wx.ALL, border=5)

        vbox.Add (st, proportion=1, flag=wx.TOP|wx.ALIGN_CENTER, border=5)
        vbox.Add (hbox, proportion=1, flag=wx.ALIGN_CENTER|wx.BOTTOM, border=10)
        self.SetSizer (vbox)

        lButton.Bind (wx.EVT_BUTTON, self.OnLeftBut)
        rButton.Bind (wx.EVT_BUTTON, self.OnRightBut)
        self.lVal = lbutVal
        self.rVal = rbutVal

    def OnLeftBut (self, e):
        self.EndModal (self.lVal)           # this return the left value to caller
        self.Destroy ()

    def OnRightBut (self, e):
        self.EndModal (self.rVal)           # this return the right value to caller
        self.Destroy ()



class new_DnD_src_obj ():
    def __init__ (self, obj):
        self.obj = obj  # Store the Object Reference for src text
        wx.EVT_LEFT_DOWN (obj, self.OnDragInit)
        wx.EVT_RIGHT_DOWN (obj, self.DummyFunc)  # bind right click to nothing!

    def DummyFunc (self, event):
        pass

    def OnDragInit (self, event):
        """ Begin a Drag Operation """
        # Create a Text Data Object, which holds the text that is to be dragged
        tdo = wx.PyTextDataObject (self.obj.GetValue())
        # Create a Drop Source Object, which enables the Drag operation
        tds = wx.DropSource (self.obj)
        tds.SetData (tdo)        # Associate the Data to be dragged with the Drop Source Object
        tds.DoDragDrop (wx.Drag_CopyOnly)  # Initiate the Drag Operation


# Define Text Drop Target class
class TextDropTarget (wx.TextDropTarget):
    """ This object implements Drop Target functionality for Text """
    def __init__ (self, target_obj, main_window, my_position):
        """ Initialize the Drop Target, passing in the Object Reference to
            indicate what should receive the dropped text """
        wx.TextDropTarget.__init__(self)
        self.target_obj = target_obj      # Store the Object Reference for dropped text
        self.main_window = main_window
        self.my_position = my_position

    def OnDropText (self, x, y, data):
        """ Implement Text Drop """
        pair = self.main_window.current_db[self.my_position]
        expected_string = pair[1]      # DnD words of lower line
        if (expected_string != data):  # do the copy if this is the expected string
            return False
        # When text is dropped, write it into the object specified
        self.target_obj.Clear ()       # clear pervious text of that box
        self.target_obj.WriteText (data)
        for i in xrange (self.main_window.N):
            expected_string = self.main_window.dnd_src_txt[i].GetValue ()    # get DnD words lower line
            if (expected_string == data):  # locate the source panel we started the DnD
                self.main_window.src_pnl[i].Show (False)  # Hide source panel which holds the word just dragged
        self.main_window.solution_counter += 1
        if (self.main_window.solution_counter == self.main_window.N):
            self.main_window.sthelpt.SetLabel (hebrew_fixed_texts.nice_you_solved_the_game)
            self.main_window.sthelpt.CentreOnParent (wx.BOTH)
        return True


# right ref word event handler. Used to capture right mouse click
class rightRefHandler (wx.EvtHandler):
    def __init__(self, parent):
        wx.EvtHandler.__init__ (self)
        wx.EVT_RIGHT_DOWN (self, self.OnMouseDown)
        self.parent = parent

    def OnMouseDown (self, evt):
        # dispatch the right click to MyFrame's method
        self.parent.acceptTop_clicks ('r')


# left ref word event handler. Used to capture left mouse click
class leftRefHandler (wx.EvtHandler):
    def __init__(self, parent):
        wx.EvtHandler.__init__ (self)
        wx.EVT_LEFT_DOWN (self, self.OnMouseDown)
        self.parent = parent

    def OnMouseDown (self, evt):
        # dispatch the left click to MyFrame's method
        self.parent.acceptTop_clicks ('l')


# main frame class
class MyFrame (wx.Frame):
    """ make a frame, inherits wx.Frame """
    def __init__ (self, show_tech_menu):
        self.__version__ = constants.__version__
        ds = wx.DisplaySize()   # get screen dimensions
        height = ds [1]
        width = ds [0]
        frame_width = (width*4)/5
        frame_height = height / 2
        # create a frame, no parent, default to wxID_ANY. The frame cannot be resized/maximized
        # the frame is generated to be positioned at the screen regarding the screen properties
        wx.Frame.__init__ (self, None, wx.ID_ANY, 'Hebrew Nirdafot', pos=(width/10, height/10), size=(frame_width, frame_height),
          style=(wx.MINIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN))

        self.N = constants.N                 # number of words in a row
        self.db = synonymDB.synonymDB()      # create data base

        panel = wx.Panel (self)
        vbox = wx.GridSizer (5, 1, height/100, 0)    # 5 rows, 1 columns, vert_gap=height/100

        #########################################
        # Create the upper reference words line #
        #########################################
        hbox1 = wx.GridSizer (1, self.N, 0, 10)   # 1 row, 6 columns, hor_gap=10
        self.ref_txt_words = list ()  # empty list of texts laying inside those panels
        self.ref_top_panels = list ()  # empty list of the top ref. panels
        for i in xrange (self.N):
            ref_words_pnl = wx.Panel (panel, style=wx.BORDER_SUNKEN)      # Create intermediate sub panel and add to the list
            ref_words_pnl.SetBackgroundColour (wx.GREEN)
            self.ref_top_panels.append (ref_words_pnl)                     # create static text and position it in the intermediate panels
            k = 'ref' + str(i)
            self.ref_txt_words.append (wx.StaticText (ref_words_pnl, label=k)) # create static text and position it in the intermediate panels
            hbox1.Add (ref_words_pnl, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)  # add intermediate panels to sizer
        vbox.Add (hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=height/100)
        ######################################################################################################################################
        ### Bind the event handler to the ref panel AND to the ref static text to enable clicking on text and on the area which surrounds it !
        ######################################################################################################################################
        self.ref_top_panels [0].       PushEventHandler (leftRefHandler(self))      # set handlers to left/right panels only !
        self.ref_top_panels [self.N-1].PushEventHandler (rightRefHandler(self))     # send parent (me) to Event handler
        self.ref_txt_words  [0].       PushEventHandler (leftRefHandler(self))      # set handlers to left/right panels only !
        self.ref_txt_words  [self.N-1].PushEventHandler (rightRefHandler(self))     # send parent (me) to Event handler

        ####################################################################
        # Create the source words list line (will be added to vbox later!) #
        ####################################################################
        hbox3 = wx.GridSizer (1, self.N, 0, 10)   # 1 row, 6 columns, hor_gap=10
        self.src_pnl = list ()         # create the list of panels holding source words
        self.dnd_src_txt = list ()     # empty list of texts laying inside those panels
        for i in xrange (self.N):
            self.src_pnl.append (wx.Panel (panel, style=wx.BORDER_SUNKEN))   # Create intermediate sub panel and add to the list
            self.src_pnl[i].SetBackgroundColour (wx.WHITE)
            r1 = str(i)
            # create text control and position it in the intermediate panels
            src_txt = wx.TextCtrl (self.src_pnl[i], value=r1, style=wx.TE_READONLY | wx.TE_CENTRE | wx.NO_BORDER)
            self.dnd_src_txt.append (src_txt)      # Add text control
            # Define a Text Control from which Text can be dragged for dropping. Define Right-Click as start of Drag
            new_DnD_src_obj (src_txt)     # new object to handle this text as DnD source
            hbox3.Add (self.src_pnl[i], flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)  # add intermediate panels to sizer

        ############################################
        # Create the target words free spaces line #
        ############################################
        hbox1 = wx.GridSizer (1, self.N, 0, 10)   # 1 row, 6 columns, hor_gap=10
        self.dnd_txt = list ()       # empty list of texts laying inside those panels
        for i in xrange (self.N):
            dnd_trgt_pnl = wx.Panel (panel, style=wx.BORDER_SUNKEN)     # Create intermediate sub panel and add to the list
            dnd_trgt_pnl.SetBackgroundColour (wx.CYAN)
            # create textCtrl and position it in the intermediate panels
            self.dnd_txt.append (wx.TextCtrl (dnd_trgt_pnl, value='?', style=wx.TE_READONLY | wx.TE_CENTRE |  wx.NO_BORDER))
            hbox1.Add (dnd_trgt_pnl, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)  # add intermediate panels to sizer
            # Define a Text Control to recieve Dropped Text. Make this control a Text Drop Target. Create a Text Drop Target object
            dt2 = TextDropTarget (self.dnd_txt[i], self, i)  # send self as main_window object
            self.dnd_txt[i].SetDropTarget (dt2) # Link the Drop Target Object to the Text Control
            self.dnd_txt[i].SetBackgroundColour (wx.CYAN)
        vbox.Add (hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=height/100)

        #####################################################################
        # Create the static text separating between DnD sources and targets #
        #####################################################################
        self.sthelpp = wx.Panel (panel)   # Create intermediate sub panel to hold the text
        self.sthelpt = wx.StaticText (self.sthelpp, label=hebrew_fixed_texts.dnd_lower_line_to_upper_line)
        vbox.Add (self.sthelpp, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=height/100)

        #################################################################
        # Add formerly Created source words list line to vertical sizer #
        #################################################################
        vbox.Add (hbox3, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=height/100)

        ##############################
        # Create the new list button #
        ##############################
        hbox1 = wx.GridSizer (1, self.N, 0, 10)   # 1 row, 6 columns, hor_gap=10
        for i in xrange (self.N-1):              # create 5 dummy texts, 1 button
            dummytext = wx.StaticText (panel, label='')
            hbox1.Add (dummytext, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)  # add empty texts to sizer
        new_list_button = wx.Button (panel, BUTN_NEW_LIST, hebrew_fixed_texts.new_list_button, style=wx.BORDER_RAISED)
        new_list_button.Bind (wx.EVT_BUTTON, self.NewList)
        hbox1.Add (new_list_button, flag=wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER, border=8)  # add the button to sizer
        vbox.Add (hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, border=height/100)

        panel.SetSizer (vbox)
        panel.Layout ()
        self.Show (True)                     # show the frame, to enable all dimensions be fixed, then center text in next loop
        for i in xrange (self.N):
            self.ref_txt_words[i].CentreOnParent (wx.BOTH)
        self.sthelpt.CentreOnParent (wx.BOTH)
        self.setInitialList ()
        self.adjustFontOfControl (None, new_list_button, hebrew_fixed_texts.new_list_button)    # parent set as None


        ######################
        # Create the menubar #
        ######################
        menuBar = wx.MenuBar ()              # Menu Bar. Create a MenuBar
        menu1 = wx.Menu ()                   # Build a Menu Object to go into the Menu Bar
        menu1.Append (MENU_FILE_EXIT, hebrew_fixed_texts.exits)
        menuBar.Append (menu1, hebrew_fixed_texts.exits)       # Place the Menu Item in the Menu Bar
        menu2 = wx.Menu ()                   # Build a Menu Object to go into the Menu Bar
        menu2.Append (MENU_SOLVE_CURRENT_LIST, hebrew_fixed_texts.solve_this_list)
        menu2.Append (MENU_HELP_HTML, hebrew_fixed_texts.help_me)
        menu2.Append (MENU_ABOUT_DLG, 'About this program')
        menuBar.Append (menu2, hebrew_fixed_texts.help) # Place the Menu Item in the Menu Bar
        menu3 = wx.Menu ()               # Build a Menu Object to go into the Menu Bar
        self.menu_show = menu3.Append (MENU_SHOW_VERSION, 'Show Versions')
        self.menu_write = menu3.Append (MENU_WRITE_VERSION, 'Write Versions to file')
        self.menu_full = menu3.Append (MENU_SHOW_FULL_LIST, 'Show Full List')
        self.menu_update = menu3.Append (MENU_CHECK_UPDATES, 'Check Updates on the Intrnt')
        menuBar.Append (menu3, 'Technical')  # Place the Menu Item in the Menu Bar
        self.menu_show.Enable (show_tech_menu)
        self.menu_write.Enable (show_tech_menu)
        self.menu_full.Enable (show_tech_menu)
        self.menu_update.Enable (show_tech_menu)
        self.SetMenuBar (menuBar)            # Place the Menu Bar on the app
        if show_tech_menu:
            self.tech_menu_state = 2
        else:
            self.tech_menu_state = 0

        wx.EVT_MENU (self, MENU_FILE_EXIT,          self.CloseWindow)  # Define Events for the Menu Items
        wx.EVT_MENU (self, MENU_SHOW_VERSION,       self.showVersions)
        wx.EVT_MENU (self, MENU_SOLVE_CURRENT_LIST, self.solveList)
        wx.EVT_MENU (self, MENU_HELP_HTML,          self.showHelp)
        wx.EVT_MENU (self, MENU_WRITE_VERSION,      self.versions2File)
        wx.EVT_MENU (self, MENU_SHOW_FULL_LIST,     self.showFullList)
        wx.EVT_MENU (self, MENU_CHECK_UPDATES,      self.checkSWupdates)
        wx.EVT_MENU (self, MENU_ABOUT_DLG,          self.aboutDialogBox)

        self.timer = wx.Timer(self)            # create a one shot timer to trigger the new list refresh
        self.Bind (wx.EVT_TIMER, self.setNewInitialList, self.timer)
        self.timer.Start (milliseconds=200, oneShot=True)


    # we had some strange phenomenon, in which at first activation the text wasn't centered at panel, so
    # we activate a timer to renew the list after first time activation and indeed it solves the problem.
    def setNewInitialList (self, event):
        self.setInitialList ()


    def resizeAlltextControls (self, height):
        for i in xrange (self.N):
            myParent = self.dnd_src_txt[i].GetParent()
            width, h = myParent.GetSize ()
            self.dnd_src_txt[i].SetSize ((width, height))       # set high enough for holding text
            self.dnd_src_txt[i].CentreOnParent (wx.BOTH)        # center the text control within its parent panel
            myParent = self.dnd_txt[i].GetParent()
            width, h = myParent.GetSize ()
            self.dnd_txt[i].SetSize ((width, height))           # set high enough for holding text
            self.dnd_txt[i].CentreOnParent (wx.BOTH)


    def setInitialList (self):
        self.current_db = self.db.getNewList(self.N)

        randomList = list (xrange (self.N))
        random.shuffle (randomList)      # Create a random shuflling of the list (0,1,2,3,4,5,6)
        # now check the list and verify that no digit stands on its 'natural' place.
        # first of all, count how many such digits exist, and save them on a list.
        non_shuffled = list ()
        for i in xrange (self.N):
            if randomList[i] == i:
                non_shuffled.append (i)

        # next loop exchange places of items until there is no shuffled index which stands on its 'natural' position
        while len (non_shuffled) > 0:
            ll = len (non_shuffled)
            if ll > 1:                                              # there is at least one pair in this list
                i = non_shuffled [ll-1]                             # we take last 2 elements
                j = non_shuffled [ll-2]
                t = randomList [i]                                  # we exchange i & j elements
                randomList [i] = randomList [j]
                randomList [j] = t
                del non_shuffled [ll-2:]                            # remove last 2 elements

            if len (non_shuffled) == 1:                             # there is only 1 element non-shuffled in this list
                i = non_shuffled [0]                                # we take the single element
                if i == 0:                                          # if it is the first element
                    t = randomList [0]                              # we exchange 0 & 1 elements
                    randomList [0] = randomList [1]
                    randomList [1] = t
                else:
                    t = randomList [i]                              # else we exchange the elements with the one left to it.
                    randomList [i] = randomList [i-1]
                    randomList [i-1] = t
                del non_shuffled [0]                                # remove the single elements

        inverseRandom = list (xrange (self.N))
        # Create an inverse list where for each I it says where I is found in the randomList
        for i in xrange (self.N):
            for j in xrange (self.N):
                if (i == randomList[j]):
                    inverseRandom[i] = j
                    break

        # next loop determines the best font size to use based on the current words list
        myParent = self.dnd_src_txt[0].GetParent()
        pwidth, pheight = myParent.GetSize()               # dimensions of the panel holding the text
        pheight = int ((pheight * 4) / 5)                  # reduce height to 80%
        pwidth = int ((pwidth * 4) / 5)                    # reduce width to 80%

        fnt = self.dnd_src_txt[0].GetFont ()               # get font of text control
        sz = 8
        fnt.SetPointSize (sz)                              # start with a very small font and enlarge it in the next loop
        font_found = False
        maxheight = 0
        while True:
            dc = wx.WindowDC (self.dnd_src_txt[0])         # create a device context of the text control
            dc.SetFont (fnt)                               # set its font identical to the text font
            for i in xrange (self.N):
                pair = self.current_db[i]
                twidth0, theight0 = dc.GetTextExtent (pair[0]) # measure text dimensions
                twidth1, theight1 = dc.GetTextExtent (pair[1]) # measure text dimensions
                if theight1 > maxheight:                       # calc max height to resize textCtrl boxes.
                    maxheight = theight1                       # It improves the appearnce of the text at Windows platform
                if (twidth0 >= pwidth) or (twidth1 >= pwidth): # we overflowed in one of the texts !
                    font_found = True
                    break                                      # break the for loop
                if (theight0 >= pheight) or (theight1 >= pheight): # we overflowed in one of the texts !
                    font_found = True
                    break                                      # break the for loop
            if font_found:
                break                                          # break the while loop

            sz += 1                                            # increase font by 1 point and loop again
            fnt.SetPointSize (sz)

        self.resizeAlltextControls (maxheight)                  # resize textControls to hold text

        # next loop actually writes the word-pairs at the text controls
        for i in xrange (self.N):
            pair = self.current_db[i]
            self.ref_txt_words[i].SetLabel (pair[0])  # build ref words upper line
            self.ref_txt_words[i].SetFont (fnt)       # set the final font for the text
            self.ref_txt_words[i].CentreOnParent (wx.BOTH) # recenter text
            pair = self.current_db[randomList[i]]
            self.dnd_src_txt[i].SetValue (pair[1])    # build DnD words lower line
            self.dnd_src_txt[i].SetFont (fnt)         # set the final font for the text
            self.dnd_src_txt[i].CentreOnParent (wx.BOTH) # recenter text
            self.src_pnl[i].Show (True)               # Show source panel which holds the source words
            self.dnd_txt[i].Clear ()                  # remove old list after solving
            self.dnd_txt[i].WriteText ('?')
            self.dnd_txt[i].SetFont (fnt)             # set the final font for the text
        self.solution_counter = 0
        self.sthelpt.SetLabel (hebrew_fixed_texts.dnd_lower_line_to_upper_line)
        self.sthelpt.CentreOnParent (wx.BOTH)          # recenter text
        self.adjustFontOfControl (self.sthelpp, self.sthelpt, hebrew_fixed_texts.dnd_lower_line_to_upper_line) # adjust font to not overflow control


    # Next function adjusts the font size of a window to be optimal
    def adjustFontOfControl (self, parentPanel, windowInstance, textOfWindow):
        # next loop determines the best font size to use based on the text to be placed on control
        if parentPanel is None:
            pwidth, pheight = windowInstance.GetSize()      # dimensions of the panel holding the text
        else:
            pwidth, pheight = parentPanel.GetSize()         # dimensions of the panel holding the text
        pheight = int ((pheight * 4) / 5)                   # reduce height to 80%
        pwidth = int ((pwidth * 4) / 5)                     # reduce width to 80%
        fnt = windowInstance.GetFont ()                     # get font of text control
        sz = 6                                              # start with a very small font and enlarge it in the next loop
        while True:
            fnt.SetPointSize (sz)
            dc = wx.WindowDC (windowInstance)               # create a device context of the text control
            dc.SetFont (fnt)                                # set its font identical to the text font
            twidth, theight = dc.GetTextExtent (textOfWindow) # measure text dimensions
            if (twidth >= pwidth) or (theight >= pheight):  # we overflowed the text !
                windowInstance.SetFont (fnt)                # set its font to final size
                windowInstance.Refresh ()
                break                                       # break the while loop
            sz += 1                                         # increase font by 1 point and loop again


    def CloseWindow (self, event):
        self.Destroy ()


    def showVersions (self, event):
        s = tech_support.createVersionsString ()
        wx.MessageBox (s, 'Versions', wx.OK)


    def aboutDialogBox (self, event):
        s = 'This program was written by Hanoch Magal\n\nI will be glad to help anyone through email address\n"hanochm2@gmail.com".\n\n'
        s += 'More details can be found at the site\n"https://sites.google.com/site/nirdafotdownloads/home".\n\n'
        s += 'Program version: ' + constants.__version__ + '\n'
        s += 'DataBase (words) versions: ' + self.db.version
        wx.MessageBox (s, 'About this program', wx.OK)


    def versions2File (self, event):
        tech_support.versions2File ('versions.txt')          # create output file
        wx.MessageBox ('File versions.txt was written', 'File was written', wx.OK)


    def solveList (self, event):
        for i in xrange (self.N):
            pair = self.current_db[i]
            self.dnd_txt[i].Clear ()                # remove old list after solving
            self.dnd_txt[i].WriteText (pair[1])
            self.src_pnl[i].Show (False)            # Hide source panel which holds the word just dragged
        self.solution_counter = self.N              # to enable 'NEW LIST' button without yes/no question
        self.sthelpt.SetLabel (hebrew_fixed_texts.soloution_displayed)
        self.sthelpt.CentreOnParent (wx.BOTH)          # recenter text


    def showHelp (self, event):
        webbrowser.open ('https://sites.google.com/site/nirdafotdownloads/')


    def NewList (self, event):
        if (self.solution_counter != self.N):
            parentRect = self.GetRect ()
            lowerRightCornerX = parentRect [0] + parentRect [2]            # X + width  -- lower right corner X position
            lowerRightCornerY = parentRect [1] + parentRect [3]            # Y + height -- lower right corner Y position
            # position the dialog box at the lower right corner of main window (the pos=() keyword arg)
            dlg = MyCustomDialog ((300,150), hebrew_fixed_texts.are_you_sure, hebrew_fixed_texts.no_cancel, hebrew_fixed_texts.yes_Iam_sure,
                                  0, 1, parent=None, title=hebrew_fixed_texts.new_list_title, pos=(lowerRightCornerX-300, lowerRightCornerY-150))
            dlg.ShowModal ()
            res = dlg.GetReturnCode ()
            if (res != 0):
                self.setInitialList ()
            return
        self.setInitialList ()    # new list for counter==N case


    def showFullList (self, event):
        full_list_frame.FullListFrame (self)


    def checkSWupdates (self, event):
        site = setup.handleGoggleSiteFiles ()
        xml_info = site.parse_URL_file ('nirdafot.xml')
        if xml_info is None:                       # This happens on any error or timeout
            GPLv3_license_acceptance.fatal_error_and_exit ('Internet access failed', "Leaving Program.")
        site_versions = xml_info [0]
        filesize      = xml_info [1]
        # convert version of the form xx.yyy to a pure integer by mult the fraction by 1000
        vengine   = site.ver_multiplied_by_1000 (site_versions[0].text)
        vdatabase = site.ver_multiplied_by_1000 (site_versions[1].text)
        lengine   = site.ver_multiplied_by_1000 (self.__version__)
        ldatabase = site.ver_multiplied_by_1000 (self.db.version)
        updateEngine   = (vengine > lengine)                # engine needs update
        updateDatabase = (vdatabase > ldatabase)            # database needs update

        if (constants.platform_is_Win is True) and (constants.Win_uses_1folder is True):
            program_size = filesize[1].text  # The size of *.zip file
        else:
            program_size = filesize[0].text  # The size of *.tar.gz file

        if updateEngine is False and updateDatabase is False:
            strv = 'Your program and DataBase are up to date\nNothing has to be done'
            wx.MessageBox (strv, 'Program is up to date', wx.OK)
            return
        elif updateEngine is False:                              # only data base needs update
            strv = 'DataBase versions are\n' + self.db.version + ' (local),\n' + site_versions[1].text + ' (at the Internet).\n' +\
                   'File size is ' + filesize[2].text + '\nUpdate ?'
            dlg = wx.MessageDialog (self, strv, 'Confirm Update', wx.OK | wx.CANCEL | wx.ICON_QUESTION)
            result = dlg.ShowModal ()
            dlg.Destroy ()
            if result != wx.ID_OK:
                return
        elif updateDatabase is False:                            # only engine needs update
            strv = 'Program versions are\n' + self.__version__ + ' (local),\n' + site_versions[0].text + ' (at the Internet).\n' +\
                   'File size is ' + program_size + '\nUpdate ?'
            dlg = wx.MessageDialog (self, strv, 'Confirm Update', wx.OK | wx.CANCEL | wx.ICON_QUESTION)
            result = dlg.ShowModal ()
            dlg.Destroy ()
            if result != wx.ID_OK:
                return
        else:
            strv  = 'Program versions are\n' + self.__version__ + ' (local),\n' + site_versions[0].text + ' (at the Internet).\n'
            strv += 'File size is ' + program_size + '\n\n'
            strv += 'DataBase versions are\n' + self.db.version + ' (local),\n' + site_versions[1].text + ' (at the Internet).\n'
            strv += 'File size is ' + filesize[2].text + '\n\nUpdate ?'
            dlg = wx.MessageDialog (self, strv, 'Confirm Update', wx.OK | wx.CANCEL | wx.ICON_QUESTION)
            result = dlg.ShowModal ()
            dlg.Destroy ()
            if result != wx.ID_OK:
                return

        reboot_game = False
        notification = ''
        if updateDatabase is True:                              # always update data base before updating the engine !!
            rc = site.update_database (site_versions[1].text)   # we need the new version to form the proper file name
            notification = 'DataBase Update: '
            if rc is True:
                reboot_game = True
                notification += 'Successfully Done'
            else:
                notification += 'Failed !'
        if updateEngine is True:
            rc = site.update_engine (site_versions[0].text, program_size, self) # we need the new version to form the proper file name.
            notification += '\nEngine Update: '
            if rc is True:
                reboot_game = True
                notification += 'Successfully Done'
            else:
                notification += 'Failed !'
        if len (notification) > 0:
            wx.MessageBox (notification, 'Updates Results', wx.OK)

        if reboot_game is True:
            mbs = 'After any upgrade Game has to be reLaunched\nGame Quits ...'
            if (constants.platform_is_Win is True) and \
               (constants.Win_uses_1folder is True) and \
               (updateEngine is True):                      # we need all 3 conditions to add next string to message
                mbs += '\nTo finish upgrade, you must MANUALLY move all files from temp folder\n' +\
                       'to the curent folder (overwrite existing files!)\n' +\
                       '(\'temp\' folder under CURRENT WORKING folder)\n'
            wx.MessageBox (mbs, 'ReLaunch', wx.OK)
            self.Destroy ()


    def acceptTop_clicks (self, argu):
        if self.tech_menu_state == 2:               # this is the 'shown' state. Do nothing and exit
            return
        if self.tech_menu_state == 1:               # this is the 'after left' state. Check if 'right'
            if argu == 'r':
                self.tech_menu_state = 2
                self.menu_show.Enable (True)
                self.menu_write.Enable (True)
                self.menu_full.Enable (True)
                self.menu_update.Enable (True)
                return
        if self.tech_menu_state == 0:               # this is the 'reset' state. Check if 'left'
            if argu == 'l':
                self.tech_menu_state = 1